package model

/*******************************************************************************
Copyright:cloud
Author:cloudapex@126.com
Version:1.0
Date:2020-07-07
Description: 角色模型
*******************************************************************************/
import (
	"errors"
	"fmt"

	"gitee.com/cloudapex/ulern/util"
	"xorm.io/xorm"
)

// => 角色表
type Role struct {
	Id     int64  `json:"id"`
	Name   string `json:"name" xorm:"varchar(128) notnull"`     // 角色名
	Order  int    `json:"order" xorm:"notnull default 0 index"` // 排序值
	State  int    `json:"state" xorm:"notnull default 1"`       // 状态(1:正常;2:失效)
	Remark string `json:"remark,omitempty" xorm:"varchar(128)"` // 备注

	CreatedAt util.TJsTime `json:"at" xorm:"index created"`
	UpdatedAt util.TJsTime `json:"-" xorm:"updated"`

	CInIds []int64    `json:"-" xorm:"-"`
	Sorte  SortFinder `json:"-" xorm:"-"`
	Pager  PageFinder `json:"-" xorm:"-"`
}

// => 角色[基本]
type RoleLable struct {
	Id   int64  `json:"id" xorm:"id"`     // 角色Id
	Name string `json:"name" xorm:"name"` // 角色名
}

// => 角色权限关联表
type RolePower struct {
	Id        int64
	RoleId    int64        `xorm:"notnull index"` // 角色Id
	PowerId   int64        `xorm:"notnull index"` // 权限Id
	CreatedAt util.TJsTime `xorm:"created"`

	CInRIds []int64 `json:"-" xorm:"-"`
}

func (this *Role) Load() (bool, error) {
	return MDB(EMDB_Permt).Get(this)
}
func (this *Role) Create() (int64, error) {
	return MDB(EMDB_Permt).Insert(this)
}
func (this *Role) Update(id int64, columns ...string) (int64, error) {
	return MDB(EMDB_Permt).ID(id).MustCols(columns...).Update(this)
}
func (this *Role) Delete(id int64) (int64, error) {
	return MDB(EMDB_Permt).ID(id).Delete(&Role{})
}
func (this *Role) Orders() map[string]string {
	return map[string]string{"id": "id", "order": "order", "at": "created_at"}
}
func (this *Role) condis(q *xorm.Session, tbl string) *xorm.Session {
	util.Cast(tbl != "", func() { tbl += "." }, nil)

	if this.Name != "" {
		q = q.Where(fmt.Sprintf("%sname like ?", tbl), "%"+this.Name+"%")
	}
	if this.State > 0 {
		q = q.Where(fmt.Sprintf("%sstate = ?", tbl), this.State)
	}
	if this.Remark != "" {
		q = q.Where(fmt.Sprintf("%sremark like ?", tbl), "%"+this.Remark+"%")
	}
	if len(this.CInIds) > 0 {
		q = q.In(fmt.Sprintf("%sid", tbl), this.CInIds)
	}
	return q
}
func (this *Role) Find() (int, []Role, error) {
	dl := []Role{}

	q := MDB(EMDB_Permt).Table(&Role{})

	q = this.condis(q, "")
	q = this.Sorte.condis(q, "", "order", this.Orders())
	q = this.Pager.condis(q, &CTimeField{ETF_Format, "created"})

	total, err := q.FindAndCount(&dl)
	return int(total), dl, err
}
func (this *Role) FindLabs() ([]RoleLable, error) {
	dl := []RoleLable{}

	q := MDB(EMDB_Permt).Table(&Role{}).Cols("id", "name")
	q = this.Sorte.condis(q, "", "order", this.Orders())

	return dl, this.condis(q, "").Find(&dl)
}
func (this *Role) VerifyIds(ids []int64) (bool, error) {
	if len(ids) == 0 {
		return true, nil
	}
	c, err := MDB(EMDB_Permt).Table(&Role{}).In("id", ids).Count()
	return c == int64(len(ids)), err
}

// ------------ RolePower
func (this *RolePower) Insert(rId int64, pIds []int64) error {
	if len(pIds) == 0 {
		return nil
	}

	items := []RolePower{}
	for _, pId := range pIds {
		items = append(items, RolePower{RoleId: rId, PowerId: pId})
	}
	for n := 0; ; n++ {
		end := (n + 1) * DEF_INSERT_BATCH_SIZE
		if end >= len(items) {
			end -= (end - len(items))
		}

		_, err := MDB(EMDB_Permt).Table(this).Insert(items[n*DEF_INSERT_BATCH_SIZE : end])
		if err != nil {
			return err
		}

		if end >= len(items) {
			break
		}
	}
	return nil
}
func (this *RolePower) Delete(rId, pId int64) (int64, error) {
	if rId == 0 && pId == 0 {
		return 0, errors.New("rId == 0 && pId == 0")
	}

	q := MDB(EMDB_Permt).Table(this)
	if rId != 0 {
		q = q.Where("role_id=?", rId)
	}
	if pId != 0 {
		q = q.Where("power_id=?", pId)
	}
	return q.Delete(&RolePower{})
}
func (this *RolePower) condis(q *xorm.Session, tbl string) *xorm.Session {
	util.Cast(tbl != "", func() { tbl += "." }, nil)

	if this.RoleId != 0 {
		q.Where(fmt.Sprintf("%srole_id = ?", tbl), this.RoleId)
	}
	if this.PowerId != 0 {
		q.Where(fmt.Sprintf("%spower_id = ?", tbl), this.PowerId)
	}
	if len(this.CInRIds) > 0 {
		q = q.In(fmt.Sprintf("%srole_id", tbl), this.CInRIds)
	}
	return q
}
func (this *RolePower) FindIds() ([]int64, error) {
	ids := []int64{}

	q := MDB(EMDB_Permt).Table(this)

	util.Cast(this.RoleId != 0, func() { q = q.Cols("power_id") }, nil)
	util.Cast(this.PowerId != 0, func() { q = q.Cols("role_id") }, nil)

	return ids, this.condis(q, "").Find(&ids)
}

// ----- UserGroupWithGroupRole
type UserGroupWithGroupRole struct {
	UserGroup `xorm:"extends"`
	GroupRole `xorm:"extends"`
}

func (this *UserGroupWithGroupRole) FindRoleIds() ([]int64, error) {
	ids := []int64{}

	q := MDB(EMDB_Permt).Table(&UserGroup{}).Cols("group_role.role_id")
	q = q.Join("INNER", "group_role", "user_group.group_id = group_role.group_id")

	q = this.UserGroup.condis(q, "user_group")
	q = this.GroupRole.condis(q, "group_role")

	return ids, q.Find(&ids)
}
